package com.ruoyi.gen.util;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.ruoyi.gen.domain.GenTable;

/**
 * 路径生成工具类
 * 
 * @author ruoyi
 */
public class PathGeneratorUtils {
    /** 微服务路径模式（默认） */
    public static final String PATH_MODE_MICROSERVICE = "microservice";

    /** 项目空间路径 */
    private static final String PROJECT_PATH = "main/java";

    /** mybatis空间路径 */
    private static final String MYBATIS_PATH = "main/resources/mapper";

    /** 前端路径 */
    private static final String VUE_PATH = "views";

    /**
     * 获取增强的文件路径
     *
     * @param template 模板文件路径
     * @param genTable 业务表信息
     * @return 生成的文件路径
     */
    public static String getEnhancedFileName(String template, GenTable genTable) {
        // 统一使用微服务模式，兼容旧的路径模式设置
        String pathMode = genTable.getPathMode();
        if (StringUtils.isEmpty(pathMode) || "default".equals(pathMode) || "module".equals(pathMode)) {
            // 兼容旧模式，统一转换为微服务模式
            pathMode = PATH_MODE_MICROSERVICE;
        }

        String result = getMicroserviceFileName(template, genTable);

        if (StringUtils.isEmpty(result)) {
            throw new RuntimeException("生成文件名失败，模板：" + template + "，路径模式：" + pathMode);
        }

        return result;
    }

    /**
     * 获取微服务模式的文件路径
     */
    private static String getMicroserviceFileName(String template, GenTable genTable) {
        String packageName = genTable.getPackageName();
        String moduleName = genTable.getModuleName();
        String className = genTable.getClassName();
        String businessName = genTable.getBusinessName();
        String modulePath = StringUtils.isNotEmpty(genTable.getModulePath()) ? genTable.getModulePath() : moduleName;

        // 微服务路径：根据前后端分离配置决定路径结构
        String javaPath, mybatisPath, vuePath;

        if (Boolean.TRUE.equals(genTable.getSeparateFrontend())) {
            // 前后端分离模式：生成微服务模块结构
            String serviceName = modulePath; // 直接使用模块路径，不添加前缀
            javaPath = serviceName + "/src/" + PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
            mybatisPath = serviceName + "/src/" + MYBATIS_PATH;
            vuePath = VUE_PATH;
        } else {
            // 传统模式：直接使用模块路径
            String serviceName = modulePath; // 直接使用模块路径，不添加前缀
            javaPath = serviceName + "/src/" + PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
            mybatisPath = serviceName + "/src/" + MYBATIS_PATH;
            vuePath = VUE_PATH;
        }

        return generateFileNameByTemplate(template, javaPath, mybatisPath, vuePath, className, businessName,
                moduleName);
    }

    /**
     * 根据模板生成文件名
     */
    private static String generateFileNameByTemplate(String template, String javaPath, String mybatisPath,
            String vuePath, String className, String businessName, String moduleName) {

        // 处理Java后端文件
        if (template.contains("domain.java.vm")) {
            return String.format("%s/domain/%s.java", javaPath, className);
        } else if (template.contains("sub-domain.java.vm")) {
            return String.format("%s/domain/%s.java", javaPath, className);
        } else if (template.contains("mapper.java.vm")) {
            return String.format("%s/mapper/%sMapper.java", javaPath, className);
        } else if (template.contains("service.java.vm") && !template.contains("serviceImpl.java.vm")) {
            return String.format("%s/service/I%sService.java", javaPath, className);
        } else if (template.contains("serviceImpl.java.vm")) {
            return String.format("%s/service/impl/%sServiceImpl.java", javaPath, className);
        } else if (template.contains("controller.java.vm")) {
            return String.format("%s/controller/%sController.java", javaPath, className);
        }
        // 处理XML文件
        else if (template.contains("mapper.xml.vm")) {
            return String.format("%s/%sMapper.xml", mybatisPath, className);
        }
        // 处理SQL文件
        else if (template.contains("sql.vm")) {
            return businessName + "Menu.sql";
        }
        // 处理前端文件
        else if (template.contains("api.js.vm")) {
            return String.format("api/%s/%s.js", moduleName, businessName);
        } else if (template.contains("index.vue.vm")) {
            return String.format("views/%s/%s/index.vue", moduleName, businessName);
        } else if (template.contains("index-tree.vue.vm")) {
            return String.format("views/%s/%s/index.vue", moduleName, businessName);
        }
        // 处理微服务配置文件
        else if (template.contains("pom.xml.vm")) {
            // 从javaPath中提取模块路径（去掉/src/main/java及包路径部分）
            String srcPath = "/src/" + PROJECT_PATH;
            int srcIndex = javaPath.indexOf(srcPath);
            if (srcIndex > 0) {
                String modulePath = javaPath.substring(0, srcIndex);
                return modulePath + "/pom.xml";
            } else {
                // 如果没有找到标准路径，直接使用模块名
                return moduleName + "/pom.xml";
            }
        } else if (template.contains("bootstrap.yml.vm")) {
            // 从mybatisPath中提取模块路径（去掉/src/main/resources/mapper部分）
            String srcPath = "/src/" + MYBATIS_PATH;
            int srcIndex = mybatisPath.indexOf(srcPath);
            if (srcIndex > 0) {
                String modulePath = mybatisPath.substring(0, srcIndex);
                return modulePath + "/src/main/resources/bootstrap.yml";
            } else {
                // 如果没有找到标准路径，直接使用模块名
                return moduleName + "/src/main/resources/bootstrap.yml";
            }
        } else if (template.contains("application.java.vm")) {
            // 主启动类放在包的根目录下
            String srcPath = "/src/" + PROJECT_PATH;
            int srcIndex = javaPath.indexOf(srcPath);
            if (srcIndex > 0) {
                String modulePath = javaPath.substring(0, srcIndex);
                // 从javaPath中提取包路径，但只取到包的根部分
                String fullJavaPath = javaPath.substring(srcIndex + srcPath.length() + 1); // 去掉/src/main/java/
                String[] pathParts = fullJavaPath.split("/");
                // 取前面的包路径部分，通常是com/ruoyi/xxx
                String packagePath = pathParts.length >= 3 ? String.join("/", pathParts[0], pathParts[1], pathParts[2])
                        : fullJavaPath;
                return modulePath + srcPath + "/" + packagePath + "/RuoYi" + StringUtils.capitalize(moduleName)
                        + "Application.java";
            } else {
                // 如果没有找到标准路径，直接使用模块名
                return moduleName + "/src/" + PROJECT_PATH + "/com/ruoyi/" + moduleName + "/RuoYi"
                        + StringUtils.capitalize(moduleName) + "Application.java";
            }
        }

        // 如果没有匹配到任何模板，抛出异常而不是返回空字符串
        throw new RuntimeException("未识别的模板类型：" + template);
    }

    /**
     * 获取增强的代码生成地址
     *
     * @param table    业务表信息
     * @param template 模板文件路径
     * @return 生成地址
     */
    public static String getEnhancedGenPath(GenTable table, String template) {
        // 判断是否为前端文件
        boolean isFrontendFile = template.contains(".vue.vm") || template.contains(".js.vm");

        String fileName = getEnhancedFileName(template, table);
        String finalPath;

        // 根据前后端分离配置选择路径
        if (Boolean.TRUE.equals(table.getSeparateFrontend()) && isFrontendFile) {
            String frontendPath = StringUtils.isNotEmpty(table.getFrontendPath()) ? table.getFrontendPath()
                    : getDefaultFrontendPath();
            finalPath = frontendPath + File.separator + fileName;
        } else if (!isFrontendFile) {
            String backendPath = StringUtils.isNotEmpty(table.getBackendPath()) ? table.getBackendPath()
                    : getDefaultBackendPath(table);
            finalPath = backendPath + File.separator + fileName;
        } else {
            // 默认路径处理
            String genPath = table.getGenPath();
            if (StringUtils.equals(genPath, "/")) {
                if (isFrontendFile) {
                    finalPath = getDefaultFrontendPath() + File.separator + fileName;
                } else {
                    finalPath = getDefaultBackendPath(table) + File.separator + fileName;
                }
            } else {
                finalPath = genPath + File.separator + fileName;
            }
        }

        // 标准化路径分隔符
        finalPath = finalPath.replace("/", File.separator).replace("\\", File.separator);
        // 处理重复的分隔符
        while (finalPath.contains(File.separator + File.separator)) {
            finalPath = finalPath.replace(File.separator + File.separator, File.separator);
        }

        return finalPath;
    }

    /**
     * 获取路径配置预览
     *
     * @param table 业务表信息
     * @return 路径预览信息
     */
    public static Map<String, Object> getPathPreview(GenTable table) {
        Map<String, Object> preview = new HashMap<>();

        // 后端文件路径预览
        preview.put("domain", getPathPreviewWithAnalysis(table, "vm/java/domain.java.vm"));
        preview.put("controller", getPathPreviewWithAnalysis(table, "vm/java/controller.java.vm"));
        preview.put("service", getPathPreviewWithAnalysis(table, "vm/java/service.java.vm"));
        preview.put("mapper", getPathPreviewWithAnalysis(table, "vm/xml/mapper.xml.vm"));

        // 前端文件路径预览 - 根据前端类型选择模板
        preview.put("api", getPathPreviewWithAnalysis(table, "vm/js/api.js.vm"));
        String vueTemplate = "element-plus".equals(table.getTplWebType()) ? "vm/vue/v3/index.vue.vm"
                : "vm/vue/index.vue.vm";
        preview.put("vue", getPathPreviewWithAnalysis(table, vueTemplate));

        // 微服务模式下添加配置文件预览
        if ("microservice".equals(table.getPathMode())) {
            preview.put("pom", getPathPreviewWithAnalysis(table, "vm/java/pom.xml.vm"));
            preview.put("bootstrap", getPathPreviewWithAnalysis(table, "vm/resources/bootstrap.yml.vm"));
            preview.put("application", getPathPreviewWithAnalysis(table, "vm/java/application.java.vm"));
        }

        return preview;
    }

    /**
     * 获取带路径分析的预览信息
     *
     * @param table    业务表信息
     * @param template 模板文件路径
     * @return 包含完整路径和分析信息的Map
     */
    private static Map<String, Object> getPathPreviewWithAnalysis(GenTable table, String template) {
        Map<String, Object> pathInfo = new HashMap<>();

        // 获取完整路径
        String fullPath = getEnhancedGenPath(table, template);
        pathInfo.put("fullPath", fullPath);

        // 分析路径组成
        Map<String, Object> analysis = analyzePathComponents(table, template, fullPath);
        pathInfo.put("analysis", analysis);

        return pathInfo;
    }

    /**
     * 分析路径组成部分
     *
     * @param table    业务表信息
     * @param template 模板文件路径
     * @param fullPath 完整路径
     * @return 路径分析信息
     */
    private static Map<String, Object> analyzePathComponents(GenTable table, String template, String fullPath) {
        Map<String, Object> analysis = new HashMap<>();

        // 判断是否为前端文件
        boolean isFrontendFile = template.contains(".vue.vm") || template.contains(".js.vm");

        // 在分析结果中标记文件类型
        analysis.put("isFrontendFile", isFrontendFile);

        if (isFrontendFile) {
            // 前端文件路径分析
            analyzeFrontendPath(table, fullPath, analysis);
        } else {
            // 后端文件路径分析
            analyzeBackendPath(table, fullPath, analysis);
        }

        return analysis;
    }

    /**
     * 分析前端文件路径
     */
    private static void analyzeFrontendPath(GenTable table, String fullPath, Map<String, Object> analysis) {
        String frontendPath = StringUtils.isNotEmpty(table.getFrontendPath()) ? table.getFrontendPath()
                : getDefaultFrontendPath();

        // 标准化路径分隔符
        String normalizedFullPath = fullPath.replace("\\", "/");
        String normalizedFrontendPath = frontendPath.replace("\\", "/");

        if (normalizedFullPath.startsWith(normalizedFrontendPath)) {
            // 默认路径部分
            analysis.put("defaultPath", normalizedFrontendPath);

            // 相对路径部分（包含用户自定义模块名）
            String relativePath = normalizedFullPath.substring(normalizedFrontendPath.length());
            if (relativePath.startsWith("/")) {
                relativePath = relativePath.substring(1);
            }

            // 前端文件使用专门的分析逻辑
            analyzeFrontendRelativePath(table, relativePath, analysis);
        } else {
            // 如果路径不以默认路径开始，整个路径都标记为自定义
            analysis.put("defaultPath", "");
            analysis.put("customPath", normalizedFullPath);
        }
    }

    /**
     * 分析后端文件路径
     */
    private static void analyzeBackendPath(GenTable table, String fullPath, Map<String, Object> analysis) {
        String backendPath = StringUtils.isNotEmpty(table.getBackendPath()) ? table.getBackendPath()
                : getDefaultBackendPath(table);

        // 标准化路径分隔符
        String normalizedFullPath = fullPath.replace("\\", "/");
        String normalizedBackendPath = backendPath.replace("\\", "/");

        if (normalizedFullPath.startsWith(normalizedBackendPath)) {
            // 默认路径部分
            analysis.put("defaultPath", normalizedBackendPath);

            // 相对路径部分（包含用户自定义模块名）
            String relativePath = normalizedFullPath.substring(normalizedBackendPath.length());
            if (relativePath.startsWith("/")) {
                relativePath = relativePath.substring(1);
            }

            // 分析相对路径中的模块名
            analyzeRelativePath(table, relativePath, analysis);
        } else {
            // 如果路径不以默认路径开始，整个路径都标记为自定义
            analysis.put("defaultPath", "");
            analysis.put("customPath", normalizedFullPath);
        }
    }

    /**
     * 分析前端相对路径中的组成部分
     */
    private static void analyzeFrontendRelativePath(GenTable table, String relativePath, Map<String, Object> analysis) {
        String moduleName = table.getModuleName(); // 前端模块名
        String businessName = table.getBusinessName();

        // 前端文件路径格式：api/{moduleName}/{businessName}.js 或
        // views/{moduleName}/{businessName}/index.vue
        analyzeFrontendPathSegments(relativePath, moduleName, businessName, analysis);
    }

    /**
     * 分析后端相对路径中的组成部分
     */
    private static void analyzeRelativePath(GenTable table, String relativePath, Map<String, Object> analysis) {
        String moduleName = table.getModuleName();
        String businessName = table.getBusinessName();
        String modulePath = table.getModulePath();

        // 查找用户自定义的模块名部分
        String customModuleName = StringUtils.isNotEmpty(modulePath) ? modulePath : moduleName;

        // 分析路径中的各个组成部分
        analyzePathSegments(relativePath, customModuleName, businessName, analysis);
    }

    /**
     * 分析前端路径段落，专门处理前端文件路径格式
     */
    private static void analyzeFrontendPathSegments(String relativePath, String moduleName, String businessName,
            Map<String, Object> analysis) {
        if (StringUtils.isEmpty(relativePath)) {
            return;
        }

        // 前端文件路径格式：api/{moduleName}/{businessName}.js 或
        // views/{moduleName}/{businessName}/index.vue
        // 先识别前缀部分（api/ 或 views/）
        String prefix = "";
        String remainingPath = relativePath;

        if (relativePath.startsWith("api/")) {
            prefix = "api/";
            remainingPath = relativePath.substring(4);
        } else if (relativePath.startsWith("views/")) {
            prefix = "views/";
            remainingPath = relativePath.substring(6);
        }

        if (StringUtils.isNotEmpty(prefix)) {
            analysis.put("beforeModule", prefix);
        }

        // 查找模块名的位置
        int moduleIndex = StringUtils.isNotEmpty(moduleName) ? remainingPath.indexOf(moduleName) : -1;

        if (moduleIndex >= 0) {
            // 找到了模块名
            if (moduleIndex > 0) {
                // 模块名前还有其他部分
                String existingBeforeModule = (String) analysis.get("beforeModule");
                String beforeModule = (existingBeforeModule != null ? existingBeforeModule : "")
                        + remainingPath.substring(0, moduleIndex);
                analysis.put("beforeModule", beforeModule);
            }

            // 模块名部分
            analysis.put("moduleName", moduleName);

            // 模块名后的部分
            int afterModuleIndex = moduleIndex + moduleName.length();
            if (afterModuleIndex < remainingPath.length()) {
                String afterModule = remainingPath.substring(afterModuleIndex);

                // 在模块名后的部分中查找业务名
                if (StringUtils.isNotEmpty(businessName) && afterModule.contains(businessName)) {
                    int businessIndex = afterModule.indexOf(businessName);

                    if (businessIndex > 0) {
                        // 业务名前的部分
                        String beforeBusiness = afterModule.substring(0, businessIndex);
                        analysis.put("beforeBusiness", beforeBusiness);
                    }

                    // 业务名部分
                    analysis.put("businessName", businessName);

                    // 业务名后的部分
                    int afterBusinessIndex = businessIndex + businessName.length();
                    if (afterBusinessIndex < afterModule.length()) {
                        String afterBusiness = afterModule.substring(afterBusinessIndex);
                        analysis.put("afterBusiness", afterBusiness);
                    }
                } else {
                    // 没有业务名，整个作为afterModule
                    analysis.put("afterModule", afterModule);
                }
            }
        } else {
            // 没有找到模块名，但可能有业务名
            if (StringUtils.isNotEmpty(businessName) && remainingPath.contains(businessName)) {
                int businessIndex = remainingPath.indexOf(businessName);

                if (businessIndex > 0) {
                    String beforeBusiness = prefix + remainingPath.substring(0, businessIndex);
                    analysis.put("standardPath", beforeBusiness);
                }

                analysis.put("businessName", businessName);

                int afterBusinessIndex = businessIndex + businessName.length();
                if (afterBusinessIndex < remainingPath.length()) {
                    String afterBusiness = remainingPath.substring(afterBusinessIndex);
                    analysis.put("afterBusiness", afterBusiness);
                }
            } else {
                // 既没有模块名也没有业务名，整个作为标准路径
                analysis.put("standardPath", relativePath);
            }
        }
    }

    /**
     * 分析后端路径段落，识别模块名和业务名
     */
    private static void analyzePathSegments(String relativePath, String moduleName, String businessName,
            Map<String, Object> analysis) {
        if (StringUtils.isEmpty(relativePath)) {
            return;
        }

        // 查找模块名的位置
        int moduleIndex = StringUtils.isNotEmpty(moduleName) ? relativePath.indexOf(moduleName) : -1;

        if (moduleIndex >= 0) {
            // 找到了模块名
            if (moduleIndex > 0) {
                // 模块名前的部分
                String beforeModule = relativePath.substring(0, moduleIndex);
                analysis.put("beforeModule", beforeModule);
            }

            // 模块名部分
            analysis.put("moduleName", moduleName);

            // 模块名后的部分
            int afterModuleIndex = moduleIndex + moduleName.length();
            if (afterModuleIndex < relativePath.length()) {
                String afterModule = relativePath.substring(afterModuleIndex);

                // 在模块名后的部分中查找业务名
                if (StringUtils.isNotEmpty(businessName) && afterModule.contains(businessName)) {
                    int businessIndex = afterModule.indexOf(businessName);

                    if (businessIndex > 0) {
                        // 业务名前的部分
                        String beforeBusiness = afterModule.substring(0, businessIndex);
                        analysis.put("beforeBusiness", beforeBusiness);
                    }

                    // 业务名部分
                    analysis.put("businessName", businessName);

                    // 业务名后的部分
                    int afterBusinessIndex = businessIndex + businessName.length();
                    if (afterBusinessIndex < afterModule.length()) {
                        String afterBusiness = afterModule.substring(afterBusinessIndex);
                        analysis.put("afterBusiness", afterBusiness);
                    }
                } else {
                    // 没有业务名，整个作为afterModule
                    analysis.put("afterModule", afterModule);
                }
            }
        } else {
            // 没有找到模块名，但可能有业务名
            if (StringUtils.isNotEmpty(businessName) && relativePath.contains(businessName)) {
                int businessIndex = relativePath.indexOf(businessName);

                if (businessIndex > 0) {
                    String beforeBusiness = relativePath.substring(0, businessIndex);
                    analysis.put("standardPath", beforeBusiness);
                }

                analysis.put("businessName", businessName);

                int afterBusinessIndex = businessIndex + businessName.length();
                if (afterBusinessIndex < relativePath.length()) {
                    String afterBusiness = relativePath.substring(afterBusinessIndex);
                    analysis.put("afterBusiness", afterBusiness);
                }
            } else {
                // 既没有模块名也没有业务名，整个作为标准路径
                analysis.put("standardPath", relativePath);
            }
        }
    }

    /**
     * 获取默认前端路径
     *
     * @return 默认前端路径
     */
    private static String getDefaultFrontendPath() {
        // 获取当前项目根目录
        String currentDir = System.getProperty("user.dir");
        File currentFile = new File(currentDir);

        // 尝试找到上级目录中的 RuoYi-Vue3 文件夹
        File parentDir = currentFile.getParentFile();
        if (parentDir != null) {
            File vue3Dir = new File(parentDir, "RuoYi-Vue3");
            if (vue3Dir.exists() && vue3Dir.isDirectory()) {
                return vue3Dir.getAbsolutePath() + File.separator + "src";
            }
        }

        // 如果找不到，返回默认路径
        return currentDir + File.separator + "frontend" + File.separator + "src";
    }

    /**
     * 获取默认后端路径
     *
     * @param table 业务表信息
     * @return 默认后端路径
     */
    private static String getDefaultBackendPath(GenTable table) {
        String currentDir = System.getProperty("user.dir");

        // 微服务模式和其他模式都返回当前目录，路径结构在文件名生成时处理
        return currentDir;
    }
}
